/************************************************************/
/*
	File: MetaClassCompiler.java

	MetaClassCompiler reads a list of classes to compile and
	generates classes for languages (java, as3 etc).
	
	The difference between this and JavaCompiler is that Java takes 
	as input a list of Java classes, whereas MetaClassCompiler takes
	an XML model and generates classes (for java, c# etc).

	Author: James Cowan
*/
/************************************************************/

package org.ems.compiler;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.ems.compiler.model.MetaClass;
import org.ems.compiler.model.MetaClassList;
import org.ems.generator.Generator;
import org.ems.generator.GeneratorException;
import org.ems.generator.GeneratorOutput;
import org.ems.generator.IGenerator;
import org.ems.generator.IGeneratorOutput;

/************************************************************/

abstract public class MetaClassCompiler extends Generator implements IGenerator
{
	protected MetaClassList		m_metaClassList;

	static protected Logger		m_log = Logger.getLogger(MetaClassCompiler.class);
	
	public MetaClassCompiler(File schemaDirectory, File schemaFile, File output)
	throws GeneratorException
	{
		super(schemaDirectory, schemaFile, output);
		
		m_metaClassList = getMetaClassList();
	}

	/************************************************************/
	/* public methods */
	/************************************************************/
	/** generate */

	public void generate(IGeneratorOutput out) throws IOException, GeneratorException
	{
		if (!m_schemaFile.exists())
		{
		String msg = m_schemaFile.getAbsolutePath()+" is missing";
		
			throw new GeneratorException(msg);		
		}
		
		FileUtils.forceMkdir(m_output);	
			
		compileMetaClassList();

	} // generate
	
	/************************************************************/
	/* protected methods */
	/************************************************************/
	/** compileMetaClassList */
	
	protected void compileMetaClassList() throws IOException, GeneratorException
	{
	MetaClass metaClasses[] = m_metaClassList.getMetaClass();
	long schemaFileDate = m_schemaFile.lastModified();
		
		for (int count=0; count<metaClasses.length; count++)
		{
		MetaClass metaClass = metaClasses[count];
		File dir = Generator.createPackageDir(m_output, m_metaClassList.getPackageName());
		File file = new File(dir, metaClass.getClassName()+getClassFileExtension());
		long fileDate = file.lastModified();
			
			if (file.exists() && fileDate >= schemaFileDate)
			{
				m_log.info(file.getAbsolutePath()+" is up to date");
				continue;
			}
				
			FileOutputStream fos = new FileOutputStream(file);
			PrintStream ps = new PrintStream(fos);
			IGenerator classGenerator = getMetaClassGenerator(m_metaClassList, metaClass);
			
			m_log.info("Create class: "+file.getAbsolutePath());
			
			classGenerator.generate(new GeneratorOutput(ps));
			ps.close();
		}
		
	} // compileMetaClassList
    
	/************************************************************/
	/** getClassFileExtension */
	
	abstract protected String getClassFileExtension();
	
	/************************************************************/
	/** getMetaClassGenerator */
	
	abstract protected IGenerator getMetaClassGenerator(MetaClassList metaClassList, MetaClass metaClass);

	/************************************************************/
	/** getMetaClassList */
	
	protected MetaClassList getMetaClassList()throws GeneratorException
	{	
        try
        {
        FileReader fr = new FileReader(m_schemaFile);
 
        	return MetaClassList.unmarshalMetaClassList(fr);
        }
        catch (Throwable e)
        {
        String schemaFileName = m_schemaFile.getAbsolutePath();
        String msg = "Cannot read "+schemaFileName+": "+e.getMessage();
        	
        	throw new GeneratorException(msg);
        }
        	
	} // getMetaClassList

} // MetaClassCompiler

/************************************************************/


